using System;
using System.IO;
using Servlets.Http;
using Servlets.Exceptions;
using System.Collections.Generic;
using Servlets.Api;

namespace Servlets.Http
{
	public class HttpRequest : IRequest
	{
		internal const string SESSION_COOKIE = "session";
		
		public IBody Body{get; private set;}
		public IValue<string> QueryString{get; private set;}
		
		public string Url{get;private set;}
		public HttpMethod HttpMethod{get;private set;}
		public HttpVersion HttpVersion{get;private set;}
		
		public Dictionary<HttpProperty, string> AllProperties {get; private set;}
		
		public Cookies Cookies {get; private set;}
		public ISession Session {get; private set;}
		
		public IRequestDispatcher RequestDispatcher {get; private set;}
		
		public IKeyable Attributes{get;private set;}
						
		protected IResponse response;
		public HttpRequest(StreamReader reader, IResponse response, IRequestDispatcher requestDispatcher)
		{
			this.response = response;
			this.RequestDispatcher = requestDispatcher;
			AllProperties = new Dictionary<HttpProperty, string>();
			Attributes = new RequestAttributes();
			ParseStream(reader);
		}
		
		public HttpRequest(string newurl, IRequest request) {
			this.Body = request.Body;
			this.QueryString = request.QueryString;
			this.Url = newurl;
			this.HttpMethod = request.HttpMethod;
			this.HttpVersion = request.HttpVersion;
			this.AllProperties = request.AllProperties;
			this.Cookies = request.Cookies;
			this.Session = request.Session;
			this.RequestDispatcher = request.RequestDispatcher;
			this.Attributes = request.Attributes;
		}
		
		private void ParseStream(StreamReader reader) {
			string line = reader.ReadLine();
			ParseFirstLine(line);
			
			while(true) {
				line = reader.ReadLine();
				if(line == "") {
					break;
				}
				
				ParsePropertyLine(line);
			}
			
			if(AllProperties.ContainsKey(HttpProperty.ContentType)) {
				ParseBody(reader);
			}
			
			ParseCookies();
			InitializeSession();
		}
		
		private void InitializeSession() {
			Cookie cookie = Cookies.TryGet(SESSION_COOKIE);
			if(cookie == null) {
				Session = new Session(response);
			} else {
				Session = new Session(cookie.Value);
			}
		}
		
		private void ParseCookies() {

			if(AllProperties.ContainsKey(HttpProperty.Cookie)) {
				string cookieValue = AllProperties[HttpProperty.Cookie];
				List<Cookie> cookies = new List<Cookie>();
				string[] split = cookieValue.Split(';');
				foreach(string cookieString in split) {
					string[] cookieSplit = cookieString.Split('=');
					string name = cookieSplit[0].Trim();
					string value = cookieSplit[1].Trim();
					Cookie cookie = new Cookie(name, value, true);
					cookies.Add(cookie);
				}
				Cookies = new Cookies(cookies);
			} else {
				Cookies = new Cookies();
			}
		}
		
		private void ParseFirstLine(string line) {
			string[] split = line.Split(' ');
			this.HttpMethod = split[0].ParseToHttpMethod();
			this.HttpVersion = HttpVersion.ParseHttpVersion(split[2]);
			
			string path = split[1];			
			string[] pathSplit = path.Split('?');
			this.Url = pathSplit[0];
			
			if(pathSplit.Length > 1) {
				string queryString = pathSplit[1];
				this.QueryString = new QueryString(queryString);
			} else {
				this.QueryString = new QueryString();
			}
		}
		
		private void ParsePropertyLine(string line) {
			string[] split = line.Split(':');
			HttpProperty key = new HttpProperty(split[0].Trim());
			string val = split[1].Trim();
			AllProperties[key] = val;
		}
		
		private void ParseBody(StreamReader reader) {
			string contentType = GetProperty(HttpProperty.ContentType);
			int contentLength = int.Parse(GetProperty(HttpProperty.ContentLength));
			
			IBody body;
			if(contentType == ContentType.APPLICATION_X_WWW_FORM_URLENCODED.Value) {
				body = new UrlEncodedBody();
			} else if (contentType.StartsWith(ContentType.MULTIPART_FORMDATA.Value)) {
				body = new FileUploadBody();
			} else {
				body = new PlainFileBody();
			}
			
			body.ParseStream(reader, contentType, contentLength);
			this.Body = body;
			Console.WriteLine ("Blah");
		}
		
		public void SetProperty(HttpProperty property, string value) {
			AllProperties[property] = value;
		}
		
		public string GetProperty(HttpProperty property) {
			return AllProperties[property];
		}
	}
}

